package server;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Server's logic. Responsible for setting up the server listener, communicating with the clients and closing connection at end.<br>
 * Default Ctor gets:
 * @param port for port connection (int)
 * @param {@link ClientHandler} Handling each client communication
 * @param numOfclients for number of clients to communicate simultaneously (int)
 * 
 * @see Thread
 * @author Barak & Tom
 */
public class MyServer extends Thread {

	int port;
	ServerSocket serverSocket;
	boolean stopServer;
	ClientHandler clientHandler;
	private int numOfClients;

	public MyServer(int port, ClientHandler clientHandler, int numOfClients) {
		this.port = port;
		stopServer = false;
		this.clientHandler = clientHandler;
		this.numOfClients = numOfClients;
	}

	public void run() {
		try {
			serverSocket = new ServerSocket(port);
			System.out.println("AutoSolver Server Started.");
			serverSocket.setSoTimeout(5000);
			ExecutorService threadPool = Executors
					.newFixedThreadPool(numOfClients);
			System.out.println("Waiting for Client...");
			while (!stopServer) {
				try {
					final Socket client = serverSocket.accept();
					System.out.println("Client Connected.\nWaiting for Client's State...");
					final BufferedReader dataFromClient = new BufferedReader(
							new InputStreamReader(client.getInputStream()));
					final PrintWriter dataToClient = new PrintWriter(
							new OutputStreamWriter(client.getOutputStream()));
					threadPool.execute(new Runnable() {
						@Override
						public void run() {
							try {
								clientHandler.handleClient(dataFromClient,
										dataToClient);
								dataFromClient.close();
								dataToClient.close();
								client.close();
							} catch (Exception e) {
								System.out.println("Server failed close connection to Client.");
							}
						}
					});
				} catch (SocketTimeoutException ste) {
					//System.out.println("Server reached timeout.");
				}
			}
			serverSocket.close();
			threadPool.shutdown();
			System.out.println("Server Stopped.");
		} catch (IOException ioe) {
			ioe.printStackTrace();
		}
	}

	public void close() {
		stopServer = true;
	}
}
